home *** CD-ROM | disk | FTP | other *** search
/ Aminet 37 / Aminet 37 (2000)(Schatztruhe)[!][Jun 2000].iso / Aminet / comm / bbs / cit_src_AD08.lha / rooma.c < prev    next >
C/C++ Source or Header  |  1998-05-10  |  26KB  |  1,030 lines

  1. /*
  2. *       rooma.c
  3. *
  4. * room code for Citadel bulletin board system.
  5. */
  6. /*
  7. *       history
  8. *
  9. * SEE THE INCREM.* FILES FOR FURTHER HISTORICAL NOTES
  10. * 84Jul12 JLS & HAW  gotoRoom() and dumpRoom() modified for <S>kip.
  11. * 84Apr04 HAW  Start 1.50a update
  12. * 83Feb24      Insert check for insufficient RAM, externs too low.
  13. * 82Dec06 CrT  2.00 release.
  14. * 82Nov05 CrT  main() splits off to become citadel.c
  15. */
  16. #include "ctdl.h"
  17. #include "math.h"
  18. #include "dos.h"
  19. /*
  20. *       Contents
  21. *
  22. * CheckForSkippedMsgs() check for skipped msgs (Mail)
  23. * CountMsgs()   counts the messages in the room.
  24. * DateSearch()    analyzes for date specs
  25. * dumpRoom()    tells us # new messages etc
  26. * fillMailRoom()    set up Mail> from log record
  27. * gotoRoom()    handles "g(oto)" command for menu
  28. * GotoNamedRoom()   goto the named room, if possible.
  29. * initCitadel()   system startup initialization
  30. * KnownRoom()   is room known?
  31. * knowRoom()    does some user know of specified room?
  32. * legalMatch()    Looks for partial matches.
  33. * listRooms()   lists known rooms
  34. * partialExist()    partial roomname matcher.
  35. * retRoom()   handle Ungoto command
  36. * roomCheck()   returns slot# of named room else ERROR
  37. * roomExists()    returns slot# of named room else ERROR
  38. * searchRooms()   searches room list for matching string
  39. * setUp()     setup the log buffer vars correctly
  40. * SkippedNewRoom()  worker function
  41. * systat()    shows current system status
  42. * tableRunner()   Applies some function to all the rooms.
  43. * UngotoMaintain()  Maintains the Ungoto list.
  44. */
  45. char        *baseRoom, BadMessages[40];
  46. int       UngotoStack[UN_STACK];
  47. char        remoteSysop = FALSE;      /* Is current user a sysop      */
  48. char        shownHidden;
  49. SListBase     Moderators =
  50.   {
  51.   NULL, ChkNtoStr, NULL, FreeNtoStr, EatNMapStr
  52.  
  53.   };
  54. int       *lPtrTab;     /* For .Ungoto    */
  55. char        BpsSet = FALSE;
  56. SListBase     BadWords =
  57.   {
  58.   NULL, FindIcky, NULL, NULL, EatIcky
  59.  
  60.   };
  61. SListBase     BadPeople =
  62.   {
  63.   NULL, FindIckyPeople, NULL, NULL, EatIckyPeople
  64.  
  65.   };
  66. extern CONFIG    cfg;   /* A buncha variables   */
  67. extern LogTable  *logTab; /* RAM index of pippuls   */
  68. extern MessageBuffer   msgBuf;
  69. extern logBuffer logBuf;  /* Pippul buffer    */
  70. extern logBuffer logTmp;  /* Pippul buffer    */
  71. extern NetBuffer netBuf;
  72. extern NetBuffer netTemp;
  73. extern struct floor     *FloorTab;
  74. extern FILE      *logfl;    /* log file descriptor    */
  75. extern FILE      *netfl;    /* Net file   */
  76. extern rTable    *roomTab;  /* RAM index of rooms   */
  77. extern aRoom     roomBuf; /* room buffer    */
  78. extern FILE      *roomfl; /* file descriptor for rooms    */
  79. extern int       thisRoom;  /* room currently in roomBuf    */
  80. extern char      loggedIn;  /* Are we logged in?    */
  81. extern char      PrintBanner;
  82. extern char      echo;    /* output flag    */
  83. extern char      prevChar;  /* Last char out    */
  84. extern char      onConsole; /* on console?    */
  85. extern char      whichIO; /* where is the I/O?    */
  86. extern int       thisSlot;  /* Current log slot   */
  87. extern char      outFlag;
  88. extern char      nextDay; /* System up before bailout?    */
  89. extern char      heldMess;
  90. extern label     oldTarget; /* Room to move messages to     */
  91. extern char      ShowNew;
  92. extern char      JustChecking;
  93. /*
  94. * DateSearch()
  95. *
  96. * This function analyzes for possible"[<|>] <date-spec>" in string.
  97. */
  98. char *DateSearch(char *str, long *before, long *after)
  99.   {
  100.   long *which;
  101.   while (*str && *str != '>' && *str != '<')
  102.   str++;
  103.   switch (*str)
  104.     {
  105.     case '>':
  106.     which = after; break;
  107.     case '<':
  108.     which = before; break;
  109.     default: return NULL;
  110.  
  111.     }
  112.   /* part of our duties is to put EOS here */
  113.   *str++ = 0;
  114.   while (*str && *str == ' ') str++;
  115.   if (*which == -1l)
  116.     {
  117.     /* if not set yet */
  118.     if (strlen(str))
  119.     ReadDate(str, which);
  120.     else
  121.     *which = logBuf.lblaston;
  122.  
  123.     }
  124.   /* now we need to find the possible location of the next date spec */
  125.   /* first, skip over current date. */
  126.   while (*str && *str != ' ' && *str != '>' && *str != '<') str++;
  127.   return str;
  128.  
  129.   }
  130. /*
  131. * dumpRoom()
  132. *
  133. * This will tell us # new messages etc.
  134. */
  135. void dumpRoom(char ShowFloor)
  136.   {
  137.   extern char HasSkipped;
  138.   int   count, newCount;
  139.   CountMsgs(&count, &newCount);
  140.   if (!loggedIn && thisRoom == MAILROOM)      /* Kludge for new users */
  141.   newCount = count = 1;     /* So they see intro.   */
  142.   if (ShowFloor)Output_Citadel_Message("FLOORN",(long)FloorTab[thisFloor].FlName,NULL,NULL);
  143.   Output_Citadel_Message("NUMMSG", count, NULL, NULL);
  144.   if (newCount > 0 && !PrintBanner)
  145.   Output_Citadel_Message("NUMNEW", newCount, NULL, NULL);
  146.   if (thisRoom == LOBBY)
  147.     {
  148.     HasSkipped = FALSE;
  149.     if (tableRunner(NSRoomHasNew, TRUE) != ERROR)
  150.     return ;
  151.     if (tableRunner(RoomHasNew, TRUE) == ERROR)
  152.     return ;
  153.     if (HasSkipped)
  154.       {
  155.       if (FloorMode)
  156.       FSkipped();
  157.       else
  158.         {
  159.         Output_Citadel_Message("SKPDRM", NULL, NULL, NULL);
  160.         ShowNew = TRUE;
  161.         JustChecking = FALSE;
  162.         tableRunner(SkippedNewRoom, TRUE);
  163.  
  164.         }
  165.  
  166.       }
  167.  
  168.     }
  169.  
  170.   }
  171. /*
  172. * CountMsgs()
  173. *
  174. * This function counts the messages in the room, total and new.
  175. */
  176. void CountMsgs(int *count, int *newCount)
  177.   {
  178.   int i;
  179.   MSG_NUMBER msgNo;
  180.   for (*newCount = *count = i = 0;
  181.   i < ((thisRoom == MAILROOM) ? MAILSLOTS : MSGSPERRM);   i++)
  182.     {
  183.     /* Msg is still in system?  Count it.   */
  184.     msgNo = roomBuf.msg[i].rbmsgNo & S_MSG_MASK;
  185.     if (msgNo >= cfg.oldest)
  186.       {
  187.       (*count)++;
  188.       /* don't boggle -- just checking against newest as of */
  189.       /* the last time we were  in this room - also against */
  190.       /* msg skip bit.            */
  191.       if ((msgNo > logBuf.lbvisit[ logBuf.lbgen[thisRoom] & CALLMASK ] &&
  192.       msgNo <= cfg.newest) || msgNo != roomBuf.msg[i].rbmsgNo)
  193.         {
  194.         (*newCount)++;
  195.  
  196.         }
  197.  
  198.       }
  199.  
  200.     }
  201.  
  202.   }
  203. /*
  204. * SkippedNewRoom()
  205. *
  206. * This is used for calls to tableRunner(), clears room's SKIP flag, if
  207. * ShowNew is TRUE it prints the room's name, else just return TRUE.
  208. */
  209. int SkippedNewRoom(int i)
  210.   {
  211.   if (roomTab[i].rtflags.SKIP == 1 && RoomHasNew(i))
  212.     {
  213.     roomTab[i].rtflags.SKIP = 0;  /* Clear. */
  214.     if (ShowNew) mPrintf(" %s ", formRoom(i, TRUE, TRUE));
  215.     if (JustChecking) return TRUE;
  216.  
  217.     }
  218.   return FALSE;
  219.  
  220.   }
  221. /*
  222. * fillMailRoom()
  223. *
  224. * This fills up the Mail room.
  225. */
  226. void fillMailRoom()
  227.   {
  228.   memcpy(roomBuf.msg, logBuf.lbMail, (long)MAIL_BULK);
  229.   noteRoom();
  230.  
  231.   }
  232. /*
  233. * gotoRoom()
  234. *
  235. * This is the menu fn to travel to a new room.
  236. * returns TRUE if room is Lobby>, else FALSE.
  237. */
  238. int gotoRoom(char *nam, char mode)
  239.   {
  240.   int  i, foundit, roomNo, s;
  241.   int  lRoom, oldFloor;
  242.   char NewFloor = FALSE;
  243.   extern int ParanoiaCount;
  244.   lRoom = thisRoom;
  245.   if (strLen(nam) == 0)
  246.     {
  247.     foundit = FALSE;  /* leaves us in Lobby> if nothing found */
  248.     if (mode != 'S')
  249.       {
  250.       SetKnown(-1, 0, thisRoom, &logBuf);
  251.       roomTab[thisRoom].rtflags.SKIP = CheckForSkippedMsgs();
  252.  
  253.       }
  254.     if (!FloorMode)
  255.       {
  256.       for (i = 0; i<MAXROOMS  &&  !foundit; i++)
  257.         {
  258.         s = knowRoom(&logBuf, i);
  259.         if (
  260.         (s == KNOW_ROOM || s == WRITE_PRIVS ||
  261.         (s != DEAD_ROOM && aide && cfg.BoolFlags.aideSeeAll &&
  262.         (!roomTab[i].rtflags.INVITE || SomeSysop())))
  263.         &&
  264.         !roomTab[i].rtflags.SKIP
  265.         )
  266.           {
  267.           if (roomTab[i].rtlastMessage >
  268.           logBuf.lbvisit[logBuf.lbgen[i] & CALLMASK] &&
  269.           roomTab[i].rtlastMessage >= cfg.oldest)
  270.             {
  271.             if (i != thisRoom)
  272.               {
  273.               foundit  = i;
  274.  
  275.               }
  276.  
  277.             }
  278.  
  279.           }
  280.  
  281.         }
  282.       getRoom(foundit);
  283.       mPrintf("%s\n ", roomBuf.rbname);
  284.  
  285.       }
  286.     else
  287.       {
  288.       NewFloor = NewRoom();
  289.       foundit = thisRoom;
  290.  
  291.       }
  292.     UngotoMaintain(lRoom);
  293.  
  294.     }
  295.   else
  296.     {
  297.     foundit = 0;
  298.     oldFloor = thisFloor;
  299.     if ((roomNo = GotoNamedRoom(nam, mode)) == ERROR)
  300.         Output_Citadel_Message("NOROOM", (long)nam, NULL, NULL);
  301.     else
  302.       {
  303.       foundit = roomNo;
  304.       if (FloorMode) NewFloor = !(oldFloor == thisFloor);
  305.  
  306.       }
  307.  
  308.     }
  309.   setUp(FALSE);
  310.   dumpRoom(NewFloor);
  311.   /* in case recover1 gets a room back for a non-existent floor */
  312.   if (!FloorTab[roomBuf.rbFlIndex].FlInuse)
  313.   roomBuf.rbFlIndex = 0;
  314.   if (thisRoom != lRoom) ParanoiaCount = 0;
  315.   return foundit;
  316.  
  317.   }
  318. /*
  319. * GotoNamedRoom()
  320. *
  321. * This function will goto the named room, if possible.
  322. */
  323. int GotoNamedRoom(char *name, char mode)
  324.   {
  325.   int roomNo;
  326.   if ((roomNo = RealGNR(name, roomExists)) == ERROR &&
  327.   (roomNo = RealGNR(name, partialExist)) == ERROR)
  328.   return ERROR;
  329.   if (roomNo != thisRoom)
  330.     {
  331.     if (mode != 'S')
  332.       {
  333.       SetKnown(-1, 0, thisRoom, &logBuf);
  334.       roomTab[thisRoom].rtflags.SKIP = CheckForSkippedMsgs();
  335.  
  336.       }
  337.     UngotoMaintain(thisRoom);
  338.     getRoom(roomNo);
  339.     /* if may have been unknown... if so, note it:      */
  340.     if (!KnownRoom(thisRoom))
  341.       {
  342.       SetKnown(0, MAXVISIT - 1, thisRoom, &logBuf);
  343.  
  344.       }
  345.  
  346.     }
  347.   return roomNo;
  348.  
  349.   }
  350. /*
  351. * RealGNR()
  352. *
  353. * This function does the real work of checking to see if a .Goto is legal.
  354. */
  355. int RealGNR(char *nam, int (*func)(char *room))
  356.   {
  357.   int roomNo;
  358.   /* non-empty room name, so now we look for it: */
  359.   if ((roomNo = roomCheck(func, nam)) == ERROR ||
  360.   roomTab[roomNo].rtflags.INVITE && !SomeSysop() &&
  361.   roomTab[roomNo].rtgen != (logBuf.lbgen[roomNo] >> GENSHIFT) &&
  362.   abs(roomTab[roomNo].rtgen - (logBuf.lbgen[roomNo] >> GENSHIFT))
  363.   != RO_OFFSET)
  364.     {
  365.     return ERROR;
  366.  
  367.     }
  368.   else
  369.     {
  370.     return roomNo;
  371.  
  372.     }
  373.  
  374.   }
  375. /*
  376. * initCitadel()
  377. *
  378. * This initializes system, returns TRUE if system is coming up normally,
  379. * false if returning from a door call.
  380. */
  381. char initCitadel()
  382.   {
  383.   SYS_FILE    tempName;
  384.   extern char ExitToMsdos;
  385.   extern long byteRate;
  386.   extern char MeetDisabled;
  387.   extern char *READ_TEXT, *VERSION, *SysVers;
  388.   int   SysVal;
  389.   char  fromDoor;
  390.   extern SListBase Arch_base, MailForward;
  391.   extern char justLostCarrier;
  392.   extern FILE *upfd;
  393.   extern int  IckyLevel;
  394.   echo = BOTH;
  395.   if (!readSysTab(TRUE, TRUE)) exit(CRASH_EXIT);/* No system table? Tacky, tacky*/
  396.   cfg.weAre = CITADEL;
  397.   if ((SysVal = systemInit()) != 0)
  398.     {
  399.     writeSysTab();
  400.     systemShutdown(SysVal);
  401.     exit(CRASH_EXIT);
  402.  
  403.     }
  404.   Output_Citadel_Message("VERSIN",NULL,NULL,NULL);
  405.   printf("This software is Public Domain, not Commercial and not Shareware.\n\n");
  406.   printf("IF YOU PAID FOR THIS SOFTWARE, SOMEONE IS RIPPING YOU OFF.\n\n");
  407.   if (access(LOCKFILE, 0) != -1)
  408.     {
  409.     printf("Lock File found!  Do you have Citadel already up?\n");
  410.     writeSysTab();  /* Save it out just in case */
  411.     systemShutdown(0);
  412.     exit(RECURSE_EXIT);
  413.  
  414.     }
  415.   SpecialMessage("Opening files         ");
  416.   /* open message files: */
  417.   InitMsgBase();
  418.   InitEvents();
  419.   initLogBuf(&logBuf);
  420.   initLogBuf(&logTmp);
  421.   initRoomBuf(&roomBuf);
  422.   initNetBuf(&netBuf);
  423.   initNetBuf(&netTemp);
  424.   initTransfers();
  425.   ReadCitInfo();
  426.   lPtrTab = (int *) GetDynamic(MAXROOMS * sizeof (int));
  427.   strCpy(oldTarget, "Aide");
  428.   baseRoom = &cfg.codeBuf[cfg.bRoom];
  429.   setUp(TRUE);
  430.   makeSysName(tempName, "CtdlLog.SYS",  &cfg.logArea);
  431.   openFile(tempName, &logfl );
  432.   makeSysName(tempName, "CtdlRoom.SYS", &cfg.roomArea);
  433.   openFile(tempName, &roomfl);
  434.   makeSysName(tempName, "CtdlArch.SYS", &cfg.roomArea);
  435.   MakeList(&Arch_base, tempName, NULL);
  436.   /**
  437.     Icky level is the first line of Badwords, filename is second line
  438.   **/
  439.   makeSysName(tempName, "BadWords.SYS", &cfg.roomArea);
  440.   if ((upfd = safeopen(tempName, READ_TEXT)) != NULL)
  441.     {
  442.     if (GetAString(msgBuf.mbtext, MAXTEXT, upfd) != NULL)
  443.     IckyLevel = atoi(msgBuf.mbtext);
  444.     if (GetAString(msgBuf.mbtext, MAXTEXT, upfd) != NULL)
  445.     strCpy(BadMessages, msgBuf.mbtext);
  446.     MakeList(&BadWords, "", upfd);
  447.     fclose(upfd);
  448.     };
  449.   /**
  450.     Icky Stuff... BadPeople.sys
  451.   **/
  452.   makeSysName(tempName, "BadPeople.SYS", &cfg.roomArea);
  453.   if ((upfd = safeopen(tempName, READ_TEXT)) != NULL)
  454.     {
  455.     MakeList(&BadPeople, "", upfd);
  456.     fclose(upfd);
  457.     };
  458.  
  459.   makeSysName(tempName, "CtdlModr.SYS", &cfg.roomArea);
  460.   MakeList(&Moderators, tempName, NULL);
  461.   if (cfg.BoolFlags.netParticipant)
  462.     {
  463.     makeSysName(tempName, "CtdlNet.SYS", &cfg.netArea);
  464.     openFile(tempName, &netfl);
  465.     NetInit();
  466.     OpenForwarding();
  467.  
  468.     }
  469.   getRoom(LOBBY);     /* load Lobby>  */
  470.   SpecialMessage("Loading Lobby...     ");
  471.   fromDoor = BackFromDoor();
  472.   if (cfg.BoolFlags.IsDoor && !fromDoor && !BpsSet)
  473.     {
  474.     printf("This is a Door C-68K.\n");
  475.     writeSysTab();
  476.     exit(RECURSE_EXIT);
  477.  
  478.     }
  479.   /* Now open the modem up */
  480.   SpecialMessage("Modem Initialization...     ");
  481.   ModemOpen((gotCarrier() && fromDoor) || cfg.BoolFlags.IsDoor);
  482.   ExitToMsdos = !ModemSetup((fromDoor ||
  483.   cfg.BoolFlags.IsDoor) && byteRate != 0);
  484.   if (!cfg.BoolFlags.IsDoor) ExitToMsdos = FALSE;
  485.   if ((fromDoor || BpsSet) && byteRate == 0)
  486.     {
  487.     DisableModem(FALSE);
  488.     whichIO = CONSOLE;
  489.  
  490.     }
  491.   else
  492.   whichIO = MODEM;
  493.   setUp(FALSE);
  494.   #ifndef MAJOR_RELEASE
  495.   if (!MeetDisabled)
  496.     {
  497.     InitBio();
  498.  
  499.     }
  500.   #endif
  501.   if (fromDoor && byteRate != 0 && !gotCarrier())
  502.   justLostCarrier = TRUE;
  503.   /* display a banner.      */
  504.   SpecialMessage("Initialization completed....");
  505.   return (char)!fromDoor;   /* if we come back from a door, don't   */
  506.   }
  507. /*
  508. * legalMatch()
  509. *
  510. * This looks for partial matches, checks legalities.
  511. */
  512. char legalMatch(int i, label target)
  513.   {
  514.   char  Equal, *endbuf;
  515.   Equal = KnownRoom(i);
  516.   if ((roomTab[i].rtflags.INUSE == 1) &&
  517.   ((aide && cfg.BoolFlags.aideSeeAll &&
  518.   !roomTab[i].rtflags.INVITE)
  519.   || Equal))
  520.     {
  521.     endbuf = lbyte(roomTab[i].rtname);
  522.     return (char)(matchString(roomTab[i].rtname, target, endbuf) != NULL);
  523.  
  524.     }
  525.   return FALSE;
  526.  
  527.   }
  528. /*
  529. * listRooms()
  530. *
  531. * This function lists known rooms.
  532. */
  533. void listRooms(char mode)
  534.   {
  535.   extern char SelDirs, SelShared, SelPriv, SelNew, Sel, SelAnon, NotForgotten;
  536.   extern char SelRO, SelArch;
  537.   shownHidden = FALSE;
  538.   switch (mode)
  539.     {
  540.     case DR_SEL:   SelDirs   = TRUE; break;
  541.     case SH_SEL:   SelShared = TRUE; break;
  542.     case PR_SEL:   SelPriv   = TRUE; break;
  543.     case ARCH_SEL: SelArch   = TRUE; break;
  544.     case ANON_SEL: SelAnon   = TRUE; break;
  545.     case READONLY: SelRO     = TRUE; break;
  546.     case INT_EXPERT:
  547.     case INT_NOVICE:
  548.     case NOT_INTRO:
  549.     SelNew = TRUE; break;
  550.     case FORGOTTEN:
  551.     NotForgotten = FALSE;
  552.     SelNew = TRUE;
  553.     break;
  554.  
  555.     }
  556.   if (FloorMode)
  557.     {
  558.     FKnown(mode);
  559.  
  560.     }
  561.   else
  562.     {
  563.     /* Else */
  564.     if (SelNew && NotForgotten)
  565.       {
  566.       Output_Citadel_Message("RMUNRD", NULL, NULL, NULL);
  567.       ShowNew = 1;
  568.  
  569.       }
  570.     else if (mode == FORGOTTEN)
  571.       {
  572.       Output_Citadel_Message("FORGRM", NULL, NULL, NULL);
  573.       ShowNew = 2;
  574.  
  575.       }
  576.     tableRunner(DispRoom, TRUE);
  577.     if (mode != INT_EXPERT && SelNew && NotForgotten)
  578.       {
  579.       Output_Citadel_Message("NOURMS", NULL, NULL, NULL);
  580.       ShowNew = FALSE;
  581.       tableRunner(DispRoom, TRUE);
  582.  
  583.       }
  584.  
  585.     }
  586.   SelArch = SelDirs = SelShared = SelRO = SelPriv = SelNew = SelAnon = FALSE;
  587.   NotForgotten = TRUE;
  588.  
  589.   }
  590. /*
  591. * tableRunner()
  592. *
  593. * This applies some function to all the rooms the user might know of.
  594. *
  595. * OnlyKnown: decides if every room is subject to the function call, or only
  596. * those the current user knows of.
  597. */
  598. int tableRunner(int (*func)(int rover), char OnlyKnown)
  599.   {
  600.   int rover;
  601.   for (rover = 0; rover < MAXROOMS; rover++)
  602.     {
  603.     if (!OnlyKnown || KnownRoom(rover))
  604.     if ((*func)(rover)) return rover;
  605.  
  606.     }
  607.   return ERROR;
  608.  
  609.   }
  610. /*
  611. * KnownRoom()
  612. *
  613. * This is called by tableRunner, returns whether room is known.  External flag
  614. * NotForgotten controls if we're doing a normal Known rooms or a list of
  615. * ZForgotten rooms.
  616. */
  617. int KnownRoom(int RoomNo)
  618.   {
  619.   extern char NotForgotten;
  620.   int s;
  621.   s = knowRoom(&logBuf, RoomNo);
  622.   if (NotForgotten)
  623.     {
  624.     return (s == KNOW_ROOM || s == WRITE_PRIVS);
  625.  
  626.     }
  627.   /* now checking for Forgotten rooms -- don't show if private room! */
  628.   if (!roomTab[RoomNo].rtflags.PUBLIC) return FALSE;
  629.   return (s == FORGOTTEN_ROOM);
  630.  
  631.   }
  632. /*
  633. * knowRoom()
  634. *
  635. * This will check to see if specified user knows given room.
  636. *
  637. * Return 0 if not know room, 2 if forgot room, 3 if know room and have write
  638. * permission (r/o rooms), 1 otherwise.
  639. */
  640. char knowRoom(logBuffer *lBuf, int i)
  641.   {
  642.   int difference;
  643.   if (!roomTab[i].rtflags.INUSE) return DEAD_ROOM;
  644.   difference = abs(roomTab[i].rtgen - (lBuf->lbgen[i] >> GENSHIFT));
  645.   return (char)( ((difference == 0) ? KNOW_ROOM :
  646.   (difference == RO_OFFSET) ? WRITE_PRIVS :
  647.   ((difference == FORGET_OFFSET) ? FORGOTTEN_ROOM :
  648.   (roomTab[i].rtflags.PUBLIC) ? KNOW_ROOM : UNKNOWN_ROOM)) );
  649.  
  650.   }
  651. /*
  652. * SetKnown()
  653. *
  654. * This sets up a known-room value.
  655. */
  656. void SetKnown(int GenVal, int Index, int Room, logBuffer *lBuf)
  657.   {
  658.   int val;
  659.   switch (GenVal)
  660.     {
  661.     case -2: val = (roomTab[Room].rtgen + (MAXGEN-1)) % MAXGEN;      break;
  662.     case -1: val = (lBuf->lbgen[Room] >> GENSHIFT);                  break;
  663.     case 0:  val = roomTab[Room].rtgen;                              break;
  664.     case RO_OFFSET:val = (roomTab[Room].rtgen + RO_OFFSET) % MAXGEN; break;
  665.     default:
  666.       val = (roomTab[Room].rtgen + FORGET_OFFSET) % MAXGEN;
  667.     };
  668.   lBuf->lbgen[Room] = (val << GENSHIFT) + Index;
  669.  
  670.   }
  671. /*
  672. * partialExist()
  673. *
  674. * This roams the list looking for a partial match.
  675. */
  676. int partialExist(label target)
  677.   {
  678.   int rover;
  679.   for (rover = (thisRoom + 1) % MAXROOMS; rover != thisRoom;
  680.   rover = (rover + 1) % MAXROOMS)
  681.   if (legalMatch(rover, target)) return rover;
  682.   return ERROR;
  683.  
  684.   }
  685. /*
  686. * retRoom()
  687. *
  688. * This is the menu Ungoto command.
  689. */
  690. void retRoom(char *roomName)
  691.   {
  692.   int slot, OldFloor;
  693.   OldFloor = thisFloor;
  694.   if (strLen(roomName) == 0)
  695.     {
  696.     if (UngotoStack[0] == -1)
  697.       {
  698.       Output_Citadel_Message("NORMUN", NULL, NULL, NULL);
  699.       return;
  700.  
  701.       }
  702.     getRoom(UngotoStack[0]);
  703.     mPrintf("%s\n ", roomBuf.rbname);
  704.     logBuf.lbgen[thisRoom] = lPtrTab[thisRoom];
  705.     /* Now pop that top element off the stack */
  706.     memmove(UngotoStack, UngotoStack + 1, (UN_STACK - 1) * sizeof(int));
  707.     UngotoStack[UN_STACK-1] = -1;   /* bottom of stack */
  708.  
  709.     }
  710.   else
  711.     {
  712.     if (
  713.     (slot = RealGNR(roomName, roomExists)) == ERROR &&
  714.     (slot = RealGNR(roomName, partialExist)) == ERROR
  715.     )
  716.       {
  717.       Output_Citadel_Message("NOROOM", (long)roomName, NULL, NULL);
  718.       return;
  719.  
  720.       }
  721.     UngotoMaintain(thisRoom);
  722.     getRoom(slot);
  723.     logBuf.lbgen[thisRoom] = lPtrTab[thisRoom];
  724.  
  725.     }
  726.   setUp(FALSE);
  727.   dumpRoom((char) FloorMode ? !(OldFloor == thisFloor) : FALSE);
  728.  
  729.   }
  730. /*
  731. * roomCheck()
  732. *
  733. * This returns slot# of named room else ERROR as determined by checker.
  734. */
  735. int roomCheck(int (*checker)(char *name), char *nam)
  736.   {
  737.   int roomNo;
  738.   if (
  739.   (roomNo = (*checker)(nam)) == ERROR
  740.   ||
  741.   (roomNo==AIDEROOM  &&  !aide)
  742.   ||
  743.   (roomTab[roomNo].rtflags.PUBLIC == 0 && !loggedIn)
  744.   )
  745.   return ERROR;
  746.   return roomNo;
  747.  
  748.   }
  749. /*
  750. * roomExists()
  751. *
  752. * This returns slot# of named room else ERROR.
  753. */
  754. int roomExists(char *room)
  755.   {
  756.   int i;
  757.   for (i = 0;  i < MAXROOMS;  i++)
  758.     {
  759.     if (
  760.     roomTab[i].rtflags.INUSE == 1   &&
  761.     strCmpU(room, roomTab[i].rtname) == SAMESTRING
  762.     )
  763.       {
  764.       return(i);
  765.  
  766.       }
  767.  
  768.     }
  769.   return(ERROR);
  770.  
  771.   }
  772. /*
  773. * searchRooms()
  774. *
  775. * This function searches for user string in list of rooms.
  776. */
  777. void searchRooms(char *target)
  778.   {
  779.   int   i;
  780.   Output_Citadel_Message("MATCHR", NULL, NULL, NULL);
  781.   outFlag = OUTOK;
  782.   for (i = 0; i < MAXROOMS;  i++)
  783.     {
  784.     if (legalMatch(i, target))
  785.       {
  786.       mPrintf(" %s ", formRoom(i, TRUE, TRUE));
  787.  
  788.       }
  789.  
  790.     }
  791.  
  792.   }
  793. /*
  794. * setUp()
  795. *
  796. * This does the initial setup based on who's logged on.
  797. */
  798. void setUp(char justIn)
  799.   {
  800.   int   g, i, j, ourSlot;
  801.   extern long DoorsUsed;
  802.   extern int  AnonMsgCount;
  803.   extern int  IckyCount;
  804.   echo = BOTH;  /* just in case */
  805.   if (justIn)
  806.     {
  807.     for (i = 0; i < UN_STACK; i++)
  808.     UngotoStack[i] = -1;
  809.     heldMess = FALSE;
  810.     IckyCount = 0;
  811.  
  812.     }
  813.   if (!loggedIn)
  814.     {
  815.     remoteSysop = FALSE;
  816.     prevChar  = ' ';
  817.     termWidth = cfg.InitColumns;
  818.     termLF    = TRUE;
  819.     termNulls = 5;
  820.     expert    = FALSE;
  821.     aide    = FALSE;
  822.     sendTime  = TRUE;
  823.     oldToo    = FALSE;
  824.     HalfDup   = FALSE;
  825.     FloorMode = FALSE;
  826.     DoorPriv  = FALSE;
  827.     if (justIn)
  828.       {
  829.       /* set up logBuf so everything is new...  */
  830.       AnonMsgCount = 0;
  831.       for (i = 0; i < MAXVISIT;  i++)  logBuf.lbvisit[i] = cfg.oldest-1l;
  832.       /* no mail for anonymous folks: */
  833.       roomTab[MAILROOM].rtlastMessage = cfg.newest;
  834.       for (i = 0; i < MAILSLOTS;  i++)
  835.       logBuf.lbMail[i].rbmsgNo = 0l;
  836.       logBuf.lbname[0] = 0;
  837.       for (i = 0; i < MAXROOMS;  i++)
  838.         {
  839.         if (roomTab[i].rtflags.PUBLIC)
  840.           {
  841.           /* make public rooms known: */
  842.           g       = roomTab[i].rtgen;
  843.           logBuf.lbgen[i] = (g << GENSHIFT) + (MAXVISIT-1);
  844.  
  845.           }
  846.         else
  847.           {
  848.           /* make private rooms unknown: */
  849.           g       = (roomTab[i].rtgen + (MAXGEN-1)) % MAXGEN;
  850.           logBuf.lbgen[i] = (g << GENSHIFT) + (MAXVISIT-1);
  851.  
  852.           }
  853.         lPtrTab[i]  = logBuf.lbgen[i];
  854.  
  855.         }
  856.  
  857.       }
  858.  
  859.     }
  860.   else
  861.     {
  862.     /* loggedIn: */
  863.     if (justIn)
  864.       {
  865.       DoorsUsed = 0l;
  866.       remoteSysop = FALSE;
  867.       /* set gen on all unknown rooms  --  INUSE or no: */
  868.       for (i = 0;  i < MAXROOMS;  i++)
  869.         {
  870.         j = abs(roomTab[i].rtgen - (logBuf.lbgen[i] >> GENSHIFT));
  871.         if (!roomTab[i].rtflags.PUBLIC && !roomTab[i].rtflags.PUBLIC)
  872.           {
  873.           /* it is private -- is it unknown? */
  874.           if (j != 0 && aide)
  875.             {
  876.             if (SomeSysop() || (cfg.BoolFlags.aideSeeAll &&
  877.             (!roomTab[i].rtflags.INVITE || SomeSysop())))
  878.             SetKnown(0, MAXVISIT - 1, i, &logBuf);
  879.  
  880.             }
  881.           else if ((j != 0 && j != RO_OFFSET) ||
  882.           (!aide && i == AIDEROOM)
  883.           )
  884.             {
  885.             /* yes -- set   gen = (realgen-1) % MAXGEN */
  886.             /* j = (roomTab[i].rtgen + (MAXGEN-1)) % MAXGEN; */
  887.             SetKnown(-2, MAXVISIT - 1, i, &logBuf);
  888.  
  889.             }
  890.  
  891.           }
  892.         else if ((logBuf.lbgen[i] >> GENSHIFT) != roomTab[i].rtgen)
  893.           {
  894.           /* newly created public room -- remember to visit it; */
  895.           j = roomTab[i].rtgen - (logBuf.lbgen[i] >> GENSHIFT);
  896.           if (j < 0)
  897.           g = -j;
  898.           else
  899.           g = j;
  900.           if (g != FORGET_OFFSET && g != RO_OFFSET)
  901.             {
  902.             SetKnown(0, 1, i, &logBuf);
  903.  
  904.             }
  905.  
  906.           }
  907.  
  908.         }
  909.       /* special kludge for Mail> room, to signal new mail:   */
  910.       roomTab[MAILROOM].rtlastMessage = 0l;
  911.       for (i = 0;  i < MAILSLOTS;  i++)
  912.       if ((logBuf.lbMail[i].rbmsgNo & (~S_MSG_MASK)) &&
  913.       (logBuf.lbMail[i].rbmsgNo & S_MSG_MASK) > cfg.oldest)
  914.       roomTab[MAILROOM].rtlastMessage = S_MSG_MASK;
  915.       if (roomTab[MAILROOM].rtlastMessage != S_MSG_MASK)
  916.       roomTab[MAILROOM].rtlastMessage =
  917.       (logBuf.lbMail[MAILSLOTS-1].rbmsgNo & S_MSG_MASK);
  918.       /* slide lbvisit array down and change lbgen entries to match: */
  919.       for (i = (MAXVISIT - 2);  i;  i--)
  920.         {
  921.         logBuf.lbvisit[i] = logBuf.lbvisit[i-1];
  922.  
  923.         }
  924.       logBuf.lbvisit[(MAXVISIT - 1)]    = cfg.oldest;
  925.       for (i = 0;  i < MAXROOMS;  i++)
  926.         {
  927.         if ((logBuf.lbgen[i] & CALLMASK)  <  (MAXVISIT-2))
  928.           {
  929.           logBuf.lbgen[i]++;
  930.  
  931.           }
  932.         lPtrTab[i]  = logBuf.lbgen[i];
  933.  
  934.         }
  935.       /* Slide entry to top of log table: */
  936.       ourSlot = logTab[thisSlot].ltlogSlot;
  937.       slideLTab(0, thisSlot);
  938.       logTab[0].ltpwhash      = hash(logBuf.lbpw);
  939.       logTab[0].ltnmhash      = hash(logBuf.lbname);
  940.       logTab[0].ltlogSlot     = ourSlot;
  941.       logTab[0].ltnewest      = cfg.newest;
  942.  
  943.       }
  944.  
  945.     }
  946.   logBuf.lbvisit[0]   = cfg.newest;
  947.   onConsole   = (whichIO == CONSOLE);
  948.   if (thisRoom == MAILROOM)   fillMailRoom();
  949.  
  950.   }
  951. /*
  952. * CheckForSkippedMsgs()
  953. *
  954. * This function does a check for skipped msgs (Mail).
  955. */
  956. char CheckForSkippedMsgs()
  957.   {
  958.   int i;
  959.   for (i = 0;  i < ((thisRoom == MAILROOM) ? MAILSLOTS : MSGSPERRM);  i++)
  960.   if ((roomBuf.msg[i].rbmsgNo & (~S_MSG_MASK)) &&
  961.   (roomBuf.msg[i].rbmsgNo & S_MSG_MASK) >= cfg.oldest)
  962.     {
  963.     roomTab[thisRoom].rtlastMessage = S_MSG_MASK;
  964.     return TRUE;
  965.  
  966.     }
  967.   noteRoom();   /* just in case */
  968.   return FALSE;
  969.  
  970.   }
  971. /*
  972. * systat()
  973. *
  974. * This function prints out current system status (.rs).
  975. */
  976. void systat()
  977.   {
  978.   extern char *VERSION, *SysVers;
  979.   int   i;
  980.   long temp;
  981.   extern long total_char_in, total_char_out;
  982.   char  buffer1[15];
  983.   char  buffer2[15];
  984.   MSG_NUMBER  average, work;
  985.   int   roomCount;
  986.   for (roomCount = i = 0; i < MAXROOMS; i++)if (roomTab[i].rtflags.INUSE) roomCount++;
  987.   Output_Citadel_Message("NODETL", NULL, NULL, NULL);
  988.   Output_Citadel_Message("DTSTMP",NULL, NULL, NULL );
  989.   if (loggedIn)
  990.     {
  991.     Output_Citadel_Message("WELCOM", NULL, NULL, NULL);
  992.     if (logBuf.lbflags.NET_PRIVS)
  993.       {
  994.       Output_Citadel_Message("NETCRD", (long)logBuf.credit, NULL, NULL);
  995.       };
  996.     mPrintf("\n ");
  997.  
  998.     };
  999.   temp = cfg.newest - cfg.oldest;
  1000.   if( temp < 0 ) temp = -temp;
  1001.   temp++;
  1002.   Output_Citadel_Message("MSGSNO"
  1003.   ,(long) PrintPretty(temp, buffer1)
  1004.   ,(long) PrintPretty(cfg.newest, buffer2)
  1005.   ,(long) cfg.maxMSector / (1024 / MSG_SECT_SIZE)  );
  1006.   Output_Citadel_Message("LOGSLR",(long)cfg.MAXLOGTAB, MAXROOMS, roomCount);
  1007.   Output_Citadel_Message("NETDAT",total_char_in, total_char_out, NULL);
  1008.   if (cfg.oldest > 1)
  1009.   work = cfg.maxMSector;
  1010.   else
  1011.   work = cfg.catSector;
  1012.   work *= MSG_SECT_SIZE;
  1013.   average = work / temp;
  1014.   Output_Citadel_Message("AVERML",average, NULL, NULL);
  1015.   Output_Citadel_Message("CCPRIV",NULL, NULL, NULL);
  1016.   }
  1017. /*
  1018. * UngotoMaintain()
  1019. *
  1020. * This function maintains the Ungoto list.
  1021. */
  1022. void UngotoMaintain(int lRoom)
  1023.   {
  1024.   /* Move stack down 1 element */
  1025.   memmove(UngotoStack + 1, UngotoStack, (UN_STACK - 1) * sizeof(int));
  1026.   /* Add new element */
  1027.   UngotoStack[0] = lRoom;
  1028.  
  1029.   }
  1030.